package com.zhuhjay.service.imchat.handler;

import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.zhuhjay.common.base.model.vo.HttpResult;
import com.zhuhjay.common.netty.handler.AbstractSocketHandler;
import com.zhuhjay.common.netty.handler.AuthParserHandler;
import com.zhuhjay.common.netty.handler.SocketLimiterHandler;
import com.zhuhjay.common.netty.util.NettySocketUtils;
import com.zhuhjay.common.redis.util.RedisUtils;
import com.zhuhjay.common.security.context.LoginUserContext;
import com.zhuhjay.service.system.model.vo.ChatUserOnlineVo;
import com.zhuhjay.service.system.service.SystemUserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Set;

import static com.zhuhjay.common.base.constant.CacheConstant.USER_ONLINE_PREFIX;

/**
 * @author ZhuHJay
 * @date 2023/7/12 12:45
 */
@Slf4j
@Component
public class UserOnlineSocketHandler extends AbstractSocketHandler<Void> {
    protected UserOnlineSocketHandler(
            SocketIOServer socketServer, AuthParserHandler authParserHandler,
            SocketLimiterHandler socketLimiterHandler) {
        super(socketServer, authParserHandler, socketLimiterHandler);
        // 只需要进行Connect和Disconnect事件监听
        socketServer.addConnectListener(this);
        socketServer.addDisconnectListener(this);
    }

    @Resource
    private SystemUserService userService;

    @Override
    protected String getEventName() {
        return "userOnline";
    }

    @Override
    protected Class<Void> getDataType() {
        return Void.class;
    }

    @Override
    public void onConnect(SocketIOClient client) {
        super.onConnect(client);
        authParserHandler.handler(client,
                () -> UID_SESSION_MAPPING.computeIfAbsent(LoginUserContext.getUid(), k -> {
                    log.info("{} 上线 {}", LoginUserContext.getUsername(), client.getSessionId());
                    String avatar = userService.getAvatar(LoginUserContext.getUsername());
                    ChatUserOnlineVo onlineVo = new ChatUserOnlineVo();
                    onlineVo.setUsername(LoginUserContext.getUsername());
                    onlineVo.setAvatar(avatar);
                    NettySocketUtils.sendEvent2AllExceptSelf(client, getEventName(), HttpResult.ok(onlineVo));
                    return client.getSessionId();
                }));
    }

    @Override
    public void onDisconnect(SocketIOClient client) {
        super.onDisconnect(client);
        // 用户登出时/logout会将uid从缓存中移除, 而后在调用此方法就无法注销了, 所以要在登出之前调用
        authParserHandler.handler(client,
                () -> UID_SESSION_MAPPING.computeIfPresent(LoginUserContext.getUid(), (k, v) -> {
                    String username = LoginUserContext.getUsername();
                    log.info("{} 下线 {}", username, client.getSessionId());
                    // 判断用户是否还有其他在线的客户端, 如果没有则发送下线消息
                    Set<String> uids = RedisUtils.getMembers4Set(USER_ONLINE_PREFIX + username);
                    long count = uids.stream().filter(uid -> !uid.equals(LoginUserContext.getUid())).count();
                    if (count == 0) {
                        log.info("{} 没有其他在线客户端, 发送下线通知", username);
                        NettySocketUtils.sendEvent2AllExceptSelf(client, getEventName(), HttpResult.ok(username));
                    }
                    return null;
                }));
    }
}
